﻿/*
 * Copyright 2014 Francois Karman
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using Quartz.WebManager.Model;
using System;
using System.Linq;

namespace Quartz.WebManager.Logic
{
    /// <summary>
    /// Manages job instances.
    /// </summary>
    public static class JobDetailManager
    {
        /// <summary>
        /// Retrieves the detail of a specific job instance.
        /// </summary>
        /// <param name="key">The key associated with the job instance.</param>
        /// <param name="withTriggers">A value indicating whether the triggers should also be provided.</param>
        /// <returns>The detail about the job instance.</returns>
        public static JobDetail RetrieveOne(JobKey key, bool withTriggers = false)
        {
            IJobDetail jobDetail = Factory.GetScheduler().GetJobDetail(key);
            JobDefinition definition = JobDefinitionManager.Cache.FirstOrDefault(d => string.Equals(d.TypeName, jobDetail.JobType.AssemblyQualifiedName, StringComparison.OrdinalIgnoreCase));
            JobDetail result = new JobDetail()
            {
                Group = key.Group,
                Name = key.Name,
                Description = jobDetail.Description,
                Definition = definition,
                JobType = definition.TypeName
            };

            foreach (var property in definition.Properties)
            {
                // TODO: Converters
                result.Properties[property.Name] = jobDetail.JobDataMap.GetString(property.Name);
            }

            if (withTriggers)
            {
                foreach (var trigger in TriggerManager.RetrieveForJob(key))
                {
                    result.Triggers.Add(trigger);
                }
            }

            return result;
        }

        /// <summary>
        /// Saves a job instance.
        /// </summary>
        /// <param name="model">The detail about the job instance.</param>
        /// <param name="replace">A value indicating whether an existing job instance should be replaced.</param>
        /// <returns>The key of the created/updated job instance.</returns>
        public static JobKey SaveOne(JobDetail model, bool replace)
        {
            if (model == null)
            {
                throw new ArgumentNullException("model");
            }
            else if (model.JobType == null)
            {
                throw new ArgumentException("The JobType property is not set", "model");
            }

            Type type = Type.GetType(model.JobType);
            if (type == null)
            {
                string format = "The JobType <{0}> is invalid or unknown";
                string message = string.Format(format, model.JobType);
                throw new ArgumentException(message, "model");
            }

            JobBuilder builder = JobBuilder
                    .Create(type)
                    .WithIdentity(model.Name, model.Group)
                    .WithDescription(model.Description)
                    .StoreDurably();

            foreach (var property in model.Definition.Properties)
            {
                // TODO: Converter
                builder.UsingJobData(property.Name, model.Properties[property.Name]);
            }

            IJobDetail detail = builder.Build();
            Factory.GetScheduler().AddJob(detail, replace);

            return detail.Key;
        }

        /// <summary>
        /// Removes a job instance.
        /// </summary>
        /// <param name="key">The key that identifies the job instance to delete.</param>
        public static void RemoveOne(JobKey key)
        {
            Factory.GetScheduler().DeleteJob(key);
        }
    }
}
